package com.tjhk.netty;

import com.tjhk.netty.mapping.HandlerMapping;
import com.tjhk.netty.mapping.handler.Handler;
import com.tjhk.netty.model.Message;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 自定义Handler需要继承netty规定好的某个HandlerAdapter(规范)
 */
public class NettyServerHandler extends ChannelInboundHandlerAdapter {

    private static final Logger log = LoggerFactory.getLogger(NettyServerHandler.class);

    private HandlerMapping handlerMapping;

    public NettyServerHandler(HandlerMapping handlerMapping) {
        this.handlerMapping = handlerMapping;
    }

    /**
     * 当客户端连接服务器完成就会触发该方法
     * @param ctx
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        Channel channel = ctx.channel();
        String channelId = channel.id().asShortText();
        //记录channel
        NettyChannelManager.add(channelId,channel);
        log.info(">>>>>>客户端[id={}]连接成功,ip:{}", channelId, channel.remoteAddress());
    }

    /**
     * 当客户端断开服务器完成就会触发该方法
     * @param ctx
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) {
        Channel channel = ctx.channel();
        String channelId = channel.id().asShortText();
        NettyChannelManager.remove(channelId);
        log.warn("<<<<<<客户端[id={}]断开连接,ip:{}", channelId, channel.remoteAddress());
    }

    /**
     * 读取客户端发送的数据
     * @param ctx 上下文对象, 含有通道channel，管道pipeline
     * @param msg 就是客户端发送的数据
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        if (!(msg instanceof Message))
            return;
        Message request = (Message) msg;
        Message response = null;
        Channel channel = ctx.channel();

        try {
            Handler handler = handlerMapping.getHandler(request.getMessageId());
            if (handler != null) {
                response = handler.invoke(request, channel);
            } else {
                log.error("Handler未注册！注册类型ID:{}",request.getMessageId());
                return;
            }
        } catch (Exception e) {
            log.warn(String.valueOf(request), e);
        }

        if (response != null)
            ctx.writeAndFlush(response);
    }

    /**
     * 数据读取完毕处理方法
     * 可用作读取后应答
     * @param ctx
     */
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) {
//        ByteBuf buf = Unpooled.copiedBuffer("Hello Client".getBytes(CharsetUtil.UTF_8));
//        ctx.channel().writeAndFlush(buf);
    }

    /**
     * 处理异常, 一般是需要关闭通道
     *
     * @param ctx
     * @param cause
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        Channel channel = ctx.channel();
//        channel.close();
        log.error("<<<<<消息处理异常客户端[id={}],ip={},cause:{}" , channel.remoteAddress(), channel.id(),cause);
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent event = (IdleStateEvent) evt;
            IdleState state = event.state();
            if (state == IdleState.READER_IDLE || state == IdleState.WRITER_IDLE) {
                Channel channel = ctx.channel();
                String channelId = channel.id().asShortText();
                NettyChannelManager.remove(channelId);
                log.warn("<<<<<<客户端[id={}]主动断开连接,ip={}", channel.id(), channel.remoteAddress());
                ctx.close();
            }
        }
    }
}
